Next | Prev | Up | Top | Contents | Index

Mapping PIO Addresses

A PIO map is a system object that represents the mapping from a location in the kernel's virtual address space to some small range of addresses on a VME or EISA bus. After creating a PIO map, a device driver can use it in the following ways:

The kernel virtual address returned by PIO mapping is not a physical memory address and is not a bus address. The kernel virtual address and the VME or EISA bus address need not have any bits in in common.

The functions used with PIO maps are summarized in Table 14-1.

Functions to Create and Use PIO Maps
FunctionHeader FilesCan SleepPurpose
pio_mapalloc(D3) pio.h & types.hYAllocate a PIO map.
pio_mapfree(D3) pio.h & types.hNFree a PIO map.
pio_badaddr(D3) pio.h & types.hNCheck for bus error when reading an address.
pio_badaddr_val(D3) pio.h & types.hNCheck for bus error when reading an address and return the value read.
pio_wbadaddr(D3) pio.h & types.hNCheck for bus error when writing to an address.
pio_wbadaddr_val(D3) pio.h & types.hNCheck for bus error when writing a specified value to an address.
pio_mapaddr(D3) pio.h & types.hNConvert a bus address to a virtual address.
pio_bcopyin(D3) pio.h & types.hYCopy data from a bus address to kernel's virtual space.
pio_bcopyout(D3) pio.h & types.hYCopy data from kernel's virtual space to a bus address.
pio_andb_rmw(D3) pio.h & types.hNByte read-and-write.
pio_andh_rmw(D3) pio.h & types.hN16-bit read-and-write.
pio_andw_rmw(D3) pio.h & types.hN32-bit read-and-write.
pio_orb_rmw(D3) pio.h & types.hNByte read-or-write.
pio_orh_rmw(D3) pio.h & types.hN16-bit read-or-write.
pio_orw_rmw(D3) pio.h & types.hN32-bit read-or-write.

A kernel-level device driver creates a PIO map by calling pio_mapalloc(). This function performs memory allocation and so can sleep. PIO maps are typically created in the pfxedtinit() entry point, where the driver first learns about the device addresses from the contents of the edt_t structure (see "Entry Point edtinit()").

The parameters to pio_mapalloc() describe the range of addresses that can be mapped in terms of

This call also specifies a "fixed" or "unfixed" map. The usual type is "fixed." For the differences, see "Fixed PIO Maps" and "Unfixed PIO Maps".

A call to pio_mapfree() releases a PIO map. PIO maps created by a loadable driver must be released in the pfxunload() entry point (see "Entry Point unload()" and "Unloading").


Testing the PIO Map

The PIO map is created from the parameters that are passed. These are not validated by pio_mapalloc(). If there is any possibility that the mapped device is not installed, not active, or improperly configured, you should test the mapped address.

The pio_badaddr() and pio_badaddr_val() functions test the mapped address to see if it is usable for input. Both functions perform the same operation: operating through a PIO map, they test a specified bus address for validity by reading 1, 2, 4, or 8 bytes from it. The pio_badaddr_val() function returns the value that it reads while making the test. This can simplify coding, as shown in Example 14-1.

Example 14-1 : Comparing pio_badaddr() to pio_badaddr_val()

unsigned int gotvalue;
piomap_t *themap;
/* Using only pio_badaddr() */
   if (!pio_badaddr(themap,CTLREG,4)
   {
      (void) pio_bcopyin(themap,CTLREG,&gotvalue,4,4,0);
      ...use "gotvalue"
/* Using pio_badaddr_val() */
   if (!pio_badaddr_val(themap,CTLREG,4,&gotvalue))
   {
      ...use "gotvalue"
The pio_wbadaddr() function tests a mapped device address for writeability. The pio_wbadaddr_val() not only tests the address but takes a specific value to write to that address in the course of testing it.


Using the Mapped Address

From a fixed PIO map you can recover a kernel virtual address that corresponds to the first bus address in the map. The pio_mapaddr() function is used for this.

You can use this address to load or store data into device registers. In the pfxmap() entry point (see "Concepts and Use of mmap()"), you can use this address with the v_mapphys() function to map the range of device addresses into the address space of a user process.

You cannot extract a kernel address from an unfixed PIO map, as explained under "Unfixed PIO Maps".


Using the PIO Map in Functions

You can apply a variety of kernel functions to any PIO map, fixed or unfixed. The pio_bcopyin() and pio_bcopyout() functions copy a range of data between memory and a fixed or unfixed PIO map. These functions are optimized to the hardware that exists, and they do all transfers in the largest size possible (32 or 64 bits per transfer). If you need to transfer data in specific sizes of 1 or 2 bytes, use direct loads and stores to the mapped addresses.

The series of functions pio_andb_rmw() and pio_orb_rmw() perform a read-modify-write cycle on the VME bus. You can use them to set or clear bits in device registers. A read-modify-write cycle is faster than a load followed by a store since it uses fewer system bus cycles.


Fixed PIO Maps

On a Challenge or Onyx system, a PIO map can be either "fixed" or "unfixed." This attribute is specified when the map is created. (On a Crimson system, only fixed maps are created regardless of which type is requested.)

The Challenge and Onyx architecture provides for a total of 15 separate, 8 MB windows on VME address space for each VME bus. Two of these are permanently reserved to the kernel, and one window is reserved for use with unfixed mappings. The remaining 12 windows are available to implement fixed PIO maps.

When the kernel creates a fixed PIO map, the map is associated with one of the 12 available VME mapping windows. The kernel tries to be clever, so that whenever a PIO map falls within an 8 MB window that already exists, the PIO map uses that window. If the desired VME address is not covered by an open window, one of the twelve windows for that bus is opened to expose a mapping for that address.

It is possible in principle to configure thirteen devices that are scattered so widely in the A32 address space that twelve, 8 MB windows cannot cover all of them. In that unlikely case, the attempt to create the thirteenth fixed PIO map will fail for lack of a mapping window.

In order to prevent this, simply configure your PIO addresses into a span of at most 96 MB per bus (see "Configuring Device Addresses").


Unfixed PIO Maps

When you create an unfixed PIO map, the map is not associated with any of the twelve mapping windows. As a result, the map cannot be queried for a kernel address that might be saved, or mapped into user space.

You can use an unfixed map with kernel functions that copy data or perform read-modify-write cycles. These functions use the one mapping window that is reserved for unfixed maps, repositioning it in VME space if necessary.

The lboot command uses an unfixed map to perform the probe and exprobe sequences from VECTOR statements (see "Configuring the System Files"). As a result, these probes do not tie up mapping windows.


Next | Prev | Up | Top | Contents | Index